﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Drawing;

namespace EpiMapit
{
    public class Circle : KmlFigureBase
	{

		public float Lat { get; set; }
		public float Lon { get; set; }
		public float RadiusInKm { get; set; }
        public float Altitude { get; set; }

        public override XElement Kml
        {
            get
            {
                return new XElement("Polygon", 
                    new XElement("altitudeMode","relativeToGround"),
                    new XElement("outerBoundaryIs",
                        new XElement("LinearRing",
                            new XElement("coordinates", CircleCoordinates()))));
            }
        }

        private string CircleCoordinates()
        {
            var builder = new StringBuilder();

			foreach (var point in GeneratePoints(ControlConstants.CirclePoints))
			{
				builder.Append(string.Format("{0},{1},{2} ", point.X, point.Y, Altitude));
			}

            return builder.ToString();
        }

		private IEnumerable<PointF> GeneratePoints(int points)
		{
			var drad = RadiusInKm * 1000 / 6378137;
			var lat1 = Lat / 180f * Math.PI;
			var long1 = Lon / 180f * Math.PI;

			for (double i = 0; i <= points; i++)
			{
				var angle = Math.PI / (points / 2) * i;
				var lat_rad = Math.Asin(Math.Sin(lat1) * Math.Cos(drad) + Math.Cos(lat1) * Math.Sin(drad) * Math.Cos(angle));
				var dlon_rad = Math.Atan2(Math.Sin(angle) * Math.Sin(drad) * Math.Cos(lat1),
					Math.Cos(drad) - Math.Sin(lat1) * Math.Sin(lat_rad));
				var lon_rad = FMod((long1 + dlon_rad + Math.PI), 2 * Math.PI) - Math.PI;

				var x = lon_rad / Math.PI * 180d;
				var y = lat_rad / Math.PI * 180d;
				yield return new PointF((float)x, (float)y);
			}
		}

        private double FMod(double x, double y)
        {
            var i = Math.Floor(x / y);
            return x - y * i;
        }

		public override BoundingBox BoundingBox
		{
			get
			{
				var north = float.MinValue;
				var south = float.MaxValue;
				var east = float.MinValue;
				var west = float.MaxValue;

				foreach (var point in GeneratePoints(4))
				{
					north = Math.Max(north, point.Y);
					south = Math.Min(south, point.Y);
					east = Math.Max(east, point.X);
					west = Math.Min(west, point.X);
				}

				return new BoundingBox((float)north, (float)south, (float)east, (float)west);
			}
		}
	}
}
